package com.google.code.eclipsercpspring;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.core.runtime.IExecutableExtensionFactory;
import org.eclipse.core.runtime.IStatus;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;

import com.google.code.eclipsercpspring.internal.BeanFactoryRegistry;
import com.google.code.eclipsercpspring.internal.EclipseSpringPlugin;
import com.google.code.eclipsercpspring.internal.LogStatus;

public class SpringExtensionFactory implements IExecutableExtension, IExecutableExtensionFactory {

   private String beanId;

   private String factoryId;

   public Object create() throws CoreException {
      try {
         BeanFactoryRegistry registry = EclipseSpringPlugin.getDefault().getBeanFactoryRegistry();
         BeanFactory factory = registry.getBeanFactory(factoryId);
         return factory.getBean(beanId);
      } catch (BeanFactoryIdNotFoundException e) {
         throw new CoreException(new LogStatus(IStatus.ERROR, "Bean factory not found: " + factoryId, e));
      } catch (NoSuchBeanDefinitionException e) {
         throw new CoreException(new LogStatus(IStatus.ERROR, "Bean not defined: " + beanId, e));
      } catch (BeansException e) {
         throw new CoreException(new LogStatus(IStatus.ERROR, "Bean retrieval error", e));
      }
   }

   private void extractAndSetData(final String beanRef) {
      final int slashIndex = beanRef.indexOf("/");
      factoryId = beanRef.substring(0, slashIndex);
      beanId = beanRef.substring(slashIndex + 1);
   }

   private boolean isInvalidBeanReference(final String beanRef) {
      int slashIndex = beanRef.indexOf('/');
      return (slashIndex <= 0) || (slashIndex == (beanRef.length() - 1));
   }

   public void setInitializationData(final IConfigurationElement config, final String propertyName, final Object data)
         throws CoreException {
      if (data instanceof String) {
         String beanRef = (String) data;

         if (isInvalidBeanReference(beanRef)) {
            throw new CoreException(new LogStatus(IStatus.ERROR,
                  "Invalid bean reference format. <factory-id>/<bean-id> required."));
         }
         extractAndSetData(beanRef);
      }
   }
}
